package weka.groupminers;

import java.util.List;

public class GroupIteration {
	
	private int numGroups;
	private Group[] groups;
	private int[] userInGroup;
	
	public GroupIteration(int n){
		userInGroup = new int[n];
		groups = new Group[n];
		numGroups = n;
		for (int i=0;i<n;i++){
			userInGroup[i]=i;
			groups[i] = new Group(i);
		}
	}
	
	
	public GroupIteration(Group[] newGroups, int t, int[] newUserInGroup) {
		this.groups = newGroups;
		this.numGroups = t;
		this.userInGroup = newUserInGroup;
	}


	public Group[] getGroups() {
		return groups;
	}

	public void setGroups(Group[] groups) {
		this.groups = groups;
	}
	
	public double getModularity(int[][] original, int[] k,int m){
		double mod=0;
		for (Group g : groups){
			mod += getModForGroup(g,original,k,m);
		}
		return mod/m;
	}


	private double getModForGroup(Group g,int[][] original, int[] k,int m) {
		double mod=0;
		double subtotal;
		int multi;
		Integer[] userArray = (Integer[]) g.getUsers().toArray(new Integer[g.getUsers().size()]);
		for (int i=0;i<userArray.length-1;i++){
			for (int j=i+1;j<userArray.length;j++){
				subtotal = original[i][j];
				multi = k[i]*k[j];
				subtotal -= multi/m;
				mod+= subtotal*2;
			}
		}
		return mod;
	}


	public GroupIteration uniteGroups(int i, int j,int[][] relations) {
		Group group1 = groups[userInGroup[i]];
		Group group2 = groups[userInGroup[j]];
		Group group3 = group1.unite(group2);
		updateRelations(group3.getUsers(),relations);
		Group[] newGroups = new Group[numGroups-1];
		int[] newUserInGroup = new int[userInGroup.length];
		for (int x=0; x<userInGroup.length;x++){
			newUserInGroup[x]=userInGroup[x];
		}
		int k=0;
		i=userInGroup[i];
		j=userInGroup[j];
		if (i<j){
			for(k=0;k<i;k++){
				newGroups[k] = groups[k].clone();
			}
			newGroups[i]=group3;
			this.updateUserInGroupWithIndex(group3,newUserInGroup,i);
			for(k=i+1;k<j;k++){
				newGroups[k] = groups[k].clone();
			}
			
			for(k=j;k<numGroups-1;k++){
				newGroups[k] = groups[k+1].clone();
				this.updateUserInGroup(k+1,newUserInGroup);
			}
		}
		else {
			for(k=0;k<j;k++){
				newGroups[k] = groups[k].clone();
			}
			newGroups[j]=group3;
			this.updateUserInGroupWithIndex(group3,newUserInGroup,j);
			for(k=j+1;k<i;k++){
				newGroups[k] = groups[k].clone();
			}
			
			for(k=i;k<numGroups-1;k++){
				newGroups[k] = groups[k+1].clone();
				this.updateUserInGroup(k+1,newUserInGroup);
			}
		}
		return new GroupIteration(newGroups,k,newUserInGroup);
	}


	private void updateRelations(List<Integer> users, int[][] relations) {
		Integer[] userArray = (Integer[]) users.toArray(new Integer[users.size()]);
		for (int i=0;i<userArray.length-1;i++){
			for (int j=i+1;j<userArray.length;j++){
				relations[userArray[i]][userArray[j]]=0;
				relations[userArray[j]][userArray[i]]=0;
			}
		}
	}


	private void updateUserInGroupWithIndex(Group group3, int[] newUserInGroup,
			int i) {
		for (Integer user : group3.getUsers()){
			newUserInGroup[user] = i;
		}
	}


	private void updateUserInGroup(int k, int[] newUserInGroup) {
		Group group = groups[k];
		for (Integer user : group.getUsers()){
			newUserInGroup[user] = k-1;
		}
	}

}
